/**
 * 
 */
package org.stars.dao.sqlmapper.parser;

import org.stars.dao.exception.parser.BracketNotBalancedException;
import org.stars.dao.sqlmapper.SqlBase;

/**
 * Check the parenthesis balance.
 * 
 * 
 * Controlla le parentesi nelle varie query. Tutte le query devono essere
 * aperte/chiuse correttamente.
 * 
 * @author Francesco Benincasa
 * 
 */
public abstract class SubParser03_CheckBracket {

	/**
	 * Esegue un controllo sulle parentesi aperte.
	 * 
	 * @param definition
	 *            dao definition
	 * @return <code>true</code> se tutto è andato bene
	 */
	public static boolean execute(SqlBase query) {
		String sql;
		String sqlId;
		String sqlMapperId = query.getSqlMapper().getId();

		sql = query.getTemplateText();
		sqlId = query.getId();

		executeCheckBracket(sqlMapperId, sqlId, sql);

		return true;
	}

	/**
	 * Il metodo controlla il numero e la sequenza delle parentesi quadre e
	 * tonde, ignorando le parentesi tra apici.
	 * 
	 * @param s
	 *            stringa da controllare
	 * @param sql
	 * @param sqlId
	 */
	static void executeCheckBracket(String sqlMapperId, String sqlId, String s) {
		String baseMessage="SqlMapper "+sqlMapperId+", Sql "+sqlId+": error during parsing of parenthesis (,[,{ :";
		String errorMessage=baseMessage+" The number of the opened parenthesis is different from the number of the closed parenthesis.";
		String sequenza = "";
		boolean errore = false;
		boolean apiceAperto = false;

		for (int idx = 0; idx < s.length() && !errore; idx++) {
			char c1 = s.charAt(idx);

			if (c1 == '\'' || c1 == '"') {
				apiceAperto = !apiceAperto;
			} else if (!apiceAperto && (c1 == '[' || c1 == '(' || c1 == '{')) {
				sequenza += c1;
			} else if (!apiceAperto && (c1 == ']' || c1 == ')' || c1 == '}')) {
				errore = sequenza.length() == 0;
				
				if (errore)
				{
					errorMessage=baseMessage+" The number of the opened parenthesis is different from the number of the closed parenthesis.";
				}

				if (!errore) {
					char c2 = sequenza.charAt(sequenza.length() - 1);

					errore = ((c1 == ']' && c2 != '[') || (c1 == ')' && c2 != '(') || (c1 == '}' && c2 != '{'));
					if (errore)
					{
						errorMessage=baseMessage+" The opened parenthesis is not balanced.";
					}
					if (!errore)
						sequenza = sequenza.substring(0, sequenza.length() - 1);
				}
			}
		}

		errore |= sequenza.length() > 0 || apiceAperto;		

		if (errore)
			throw (new BracketNotBalancedException(errorMessage));
		
	}
}
